package org.ucas.faker.web.fetcher;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class FetchResult {

  final List<Map> data;

  
  public FetchResult(List<Map> data) {
    this.data = data;
  }

  public Integer size() {
    return data == null? 0 : data.size();
  }

  @SuppressWarnings("unchecked")
  public <T> List<T> column(String name) {
    if(data == null) return null;
    List<T> res = new ArrayList<>();
    boolean exist = false;
    for(Map item : data) {
      if(item.containsKey(name)) exist = true;
      T t = (T) item.getOrDefault(name,null);
      res.add(t);
    }
    return exist? res : (data.size() == 0? res: null);
  }

  public <T> List<T> entities(Class<T> clazz) throws InstantiationException, IllegalAccessException {
    if(data == null) return null;
    List<T> res = new ArrayList<>();
    for(Map item : data) res.add(entity(item,clazz));
    return res;
  }

  private <T> T entity(Map map, Class<T> clazz) throws IllegalAccessException, InstantiationException {
    T res = clazz.newInstance();
    for(Field field:clazz.getDeclaredFields()) {
      field.setAccessible(true);
      if(map.containsKey(field.getName()))
        field.set(res,map.get(field.getName()));
    }
    return res;
  }

  @SuppressWarnings("unchecked")
  public <T> void sort(String key, Comparator<T> comp) {
    data.sort(new Comparator<Map>() {
      @Override
      public int compare(Map l, Map r) {
        T left = (T) l.getOrDefault(key,null);
        T right = (T) r.getOrDefault(key,null);

        if(left == right && left == null) return 0;
        else if(left == null) return -1;
        else if(right == null) return 1;
        else return comp.compare(left,right);
      }
    });
  }

  public void sort(String key, boolean ascend) {
    data.sort(new Comparator<Map>() {
      @Override
      public int compare(Map l, Map r) {
        if(ascend) return ((Long) l.get(key)) < ((Long) r.get(key)) ? 1 : -1;
        else return ((Long) l.get(key)) < ((Long) r.get(key)) ? -1 : 1;
      }
    });
  }
}
